package setting

import (
	"fmt"

	"github.com/fsnotify/fsnotify"

	"github.com/spf13/viper"
)

//新版本 定义一个全局变量Conf 类型为 &AppConfig
//AppConfig类型变量的指针
/**
做法： 读取配置文件的内容后，存入内部定义的结构体中
目的：让配置信息更直观的展示，
	有利于解决 配置项很多的问题
	便于团队人员来维护项目

*/
//全局变量，用来保存程序的所有配置信息
var Conf = new(AppConfig)

type AppConfig struct {
	Name             string `mapstructure:"name"`
	Mode             string `mapstructure:"mode"`
	Version          string `mapstructure:"version"`
	Port             string `mapstructure:"port"`
	*LogConfig       `mapstructure:"log"`
	*MySQLConfig     `mapstructure:"mysql"`
	*RedisConfig     `mapstructure:"redis"`
	*SnowFlakeConfig `mapstructure:"snowflake"`
}

type LogConfig struct {
	Level    string `mapstructure:"level"`
	Filename string `mapstructure:"filename"`
	MaxSize  int    `mapstructure:"max_size"`
	MaxAge   int    `mapstructure:"max_age"`
	MaxBucks int    `mapstructure:"max_bucks"`
}

type MySQLConfig struct {
	Host          string `mapstructure:"host"`
	Port          int    `mapstructure:"port"`
	User          string `mapstructure:"user"`
	Password      string `mapstructure:"password"`
	DbName        string `mapstructure:"db_name"`
	MaxOpenConnns int    `mapstructure:"max_open_conns"`
	MaxIdleConnns int    `mapstructure:"max_idle_conns"`
}

type RedisConfig struct {
	Host     string `mapstructure:"host"`
	Password string `mapstructure:"password"`
	Port     int    `mapstructure:"port"`
	DB       int    `mapstructure:"db"`
	PoolSize int    `mapstructure:"pool_size"`
}

//雪花算法配置
type SnowFlakeConfig struct {
	InitTime  string `mapstructure:"init_time"`
	MachineId uint16 `mapstructure:"machine_id"`
}

func Init() (err error) {
	//方式一：直接指定配置文件路径（相对路径或绝对路径）
	//viper.SetConfigFile("./conf/config.yaml")

	//方式二：指定配置文件名和配置文件的位置，让viper自行查找可用的配置文件
	//配置文件名不需要后缀
	//配置文件位置可以配多个

	viper.SetConfigName("config") //指定配置文件名称（不需要后缀）
	//指定配置文件类型  由于本项目中 配置文件在本地 所以该语句 可以注释
	//基本是配合远程配置中心使用 告诉viper当前的数据使用什么格式去解析
	viper.SetConfigType("yaml")
	viper.AddConfigPath("./conf/") //指定查找配置文件的路径（此处为相对路径）
	err = viper.ReadInConfig()     //读取配置信息
	if err != nil {
		fmt.Printf("viper.ReadInConfig() failed, err:%v\n", err)
		return
	}
	//将从配置文件中读到的信息 反序列化到定义的结构体变量Conf中
	if err := viper.Unmarshal(Conf); err != nil {
		fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
	}

	//监控配置文件变化
	viper.WatchConfig()
	//对配置文件变化后做的处理
	viper.OnConfigChange(func(in fsnotify.Event) {
		fmt.Println("配置文件修改了...")
		//当配置文件中的信息变化时 将从配置文件中读到的信息 反序列化到定义的结构体变量Conf中
		if err := viper.Unmarshal(Conf); err != nil {
			fmt.Printf("viper.Unmarshal failed, err:%v\n", err)
		}
	})
	return

}

//旧版本 将配置文件的信息 读取到viper中
//func Init() (err error) {
//	viper.SetConfigName("config")  //指定配置文件名称（不需要后缀）
//	viper.SetConfigType("yaml")    //指定配置文件类型
//	viper.AddConfigPath("./conf/") //指定查找配置文件的路径（此处为相对路径）
//	err = viper.ReadInConfig()     //读取配置信息
//	if err != nil {
//		fmt.Printf("viper.ReadInConfig() failed, err:%v\n", err)
//		return
//	}
//	//监控配置文件变化
//	viper.WatchConfig()
//	//对配置文件变化后做的处理
//	viper.OnConfigChange(func(in fsnotify.Event) {
//		fmt.Println("配置文件修改了...")
//	})
//	return
//
//}
